﻿using Common.Exceptions;
using Common.Logger;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

namespace Common.Web
{
#pragma warning disable CS1591
    public class GlobalExceptionFilter : IExceptionFilter
    {
        private readonly IConfiguration configuration;
        public GlobalExceptionFilter(IConfiguration _configuration)
        {
            this.configuration = _configuration;
        }
        public void OnException(ExceptionContext context)
        {
            FuncResult result = new FuncResult()
            {
                Code = "0500",
                Message = "系统访问人太多了，请稍后再试！",
            };
            Type currentExType = context.Exception.GetType();
            //是否为开发者主动抛出的异常，如果异常Exception继承自JaredsException，则认为此异常是故意抛出的
            bool exceptionOnPurpose = typeof(JaredsException).IsAssignableFrom(currentExType);
            if (Utils.IsDevelopment || exceptionOnPurpose)
            {
                result.Message = context.Exception.Message;
            };
            context.ExceptionHandled = true;
            if (!exceptionOnPurpose)
            {
                context.HttpContext.Response.Headers.Add("x-exception", "true");
                context.HttpContext.Features.Set(new HttpStatusCodeWrapperFeature(HttpStatusCode.InternalServerError));
            }

            if (context.Exception is SpecificStatusCodeException ssc)
            {
                context.Result = new StatusCodeObjectResult(ssc.StatusCode, result);
                int code = (int)ssc.StatusCode;
                if (code != 0)
                {
                    result.Code = code.ToString().PadLeft(4, '0');
                }
            }
            else if (currentExType.FullName == "Refit.ApiException")
            {
                int code = (int)currentExType.GetProperty("StatusCode").GetValue(context.Exception);
                result.Code = code == 0 ? "0500" : code.ToString().PadLeft(4, '0');
                if (code == 401)
                {
                    result.Message = "token已失效，请重新登录";
                }
                context.Result = new StatusCodeObjectResult((HttpStatusCode)code, result);
            }
            else
            {
                var objResult = new ObjectResult(result);
                if ("true".Equals(configuration["RestfulExceptionFilter"], StringComparison.OrdinalIgnoreCase))
                {
                    objResult.StatusCode = (int)HttpStatusCode.InternalServerError;
                }
                context.Result = objResult;
            }

            Log<GlobalExceptionFilter>.Error($"GlobalExceptionFilter:{context.Exception.Message}", context.Exception);
            if (context.Exception.InnerException != null)
            {
                Log<GlobalExceptionFilter>.Error($"GlobalInnerExceptionFilter:{context.Exception.InnerException.Message}", context.Exception.InnerException);
            }
            FailureLogFilterAttribute.LogFailure(result, context.HttpContext);
        }
    }
    /// <summary>
    /// http状态码封装功能
    /// </summary>
    internal class HttpStatusCodeWrapperFeature
    {
        public HttpStatusCodeWrapperFeature(HttpStatusCode statusCode)
        {
            this.OriStatusCode = statusCode;
        }
        public HttpStatusCode OriStatusCode { get; set; }
    }
    internal class StatusCodeObjectResult : ObjectResult
    {
        public StatusCodeObjectResult(HttpStatusCode statusCode, object data) : base(data)
        {
            this.StatusCode = (int)statusCode;
        }
    }
#pragma warning restore CS1591

}
